#!/usr/bin/env node

/**
 * TodoList应用自动化测试主入口
 * 整合API和前端测试，生成详细的测试报告
 */

const fs = require('fs-extra');
const path = require('path');
const chalk = require('chalk');
const moment = require('moment');
const config = require('./config/test-config');
const TestUtils = require('./utils/test-utils');
const ApiTestRunner = require('./tests/api/api-test-runner');
const FrontendTestRunner = require('./tests/frontend/frontend-test-runner');

class MainTestRunner {
  constructor() {
    this.testUtils = new TestUtils(config);
    this.startTime = null;
    this.endTime = null;
    this.allResults = {
      api: [],
      frontend: [],
      summary: {
        total: 0,
        passed: 0,
        failed: 0,
        duration: 0,
        modules: {}
      }
    };
  }

  /**
   * 运行所有测试
   */
  async runAllTests() {
    this.startTime = Date.now();
    
    console.log(chalk.bold.blue('🚀 TodoList应用自动化测试开始'));
    console.log(chalk.gray('='.repeat(80)));
    console.log(chalk.cyan(`测试时间: ${moment().format('YYYY-MM-DD HH:mm:ss')}`));
    console.log(chalk.cyan(`服务器地址: ${config.server.baseUrl}`));
    console.log(chalk.cyan(`前端地址: ${config.frontend.baseUrl}`));
    console.log(chalk.gray('='.repeat(80)));

    try {
      // 1. 检查测试环境
      await this.checkTestEnvironment();
      
      // 2. 运行API测试
      await this.runApiTests();
      
      // 3. 运行前端测试
      await this.runFrontendTests();
      
      // 4. 生成测试报告
      await this.generateTestReport();
      
    } catch (error) {
      console.error(chalk.red(`\n❌ 测试执行失败: ${error.message}`));
      process.exit(1);
    } finally {
      this.endTime = Date.now();
      await this.printFinalSummary();
    }
  }

  /**
   * 检查测试环境
   */
  async checkTestEnvironment() {
    console.log(chalk.yellow('\n🔍 检查测试环境...'));
    
    try {
      // 检查服务器连接
      const httpClient = this.testUtils.createHttpClient();
      
      try {
        await httpClient.get('/health', { timeout: 5000 });
        console.log(chalk.green('✅ 服务器连接正常'));
      } catch (error) {
        console.log(chalk.yellow('⚠️  服务器连接失败，将跳过API测试'));
        console.log(chalk.gray(`   错误信息: ${error.message}`));
      }
      
      // 检查前端服务
      try {
        const response = await fetch(config.frontend.baseUrl, { 
          method: 'HEAD',
          timeout: 5000 
        });
        if (response.ok) {
          console.log(chalk.green('✅ 前端服务正常'));
        } else {
          throw new Error(`HTTP ${response.status}`);
        }
      } catch (error) {
        console.log(chalk.yellow('⚠️  前端服务连接失败，将跳过前端测试'));
        console.log(chalk.gray(`   错误信息: ${error.message}`));
      }
      
      // 检查测试结果目录
      await fs.ensureDir(path.join(__dirname, 'results'));
      console.log(chalk.green('✅ 测试结果目录已准备'));
      
    } catch (error) {
      console.error(chalk.red(`环境检查失败: ${error.message}`));
      throw error;
    }
  }

  /**
   * 运行API测试
   */
  async runApiTests() {
    console.log(chalk.bold.cyan('\n🔧 开始API功能测试'));
    console.log(chalk.gray('-'.repeat(60)));
    
    try {
      const apiRunner = new ApiTestRunner();
      await apiRunner.runAllTests();
      
      // 收集API测试结果
      this.allResults.api = apiRunner.testUtils.testResults;
      
      console.log(chalk.green('\n✅ API测试完成'));
    } catch (error) {
      console.error(chalk.red(`\n❌ API测试失败: ${error.message}`));
      // 不中断整个测试流程
    }
  }

  /**
   * 运行前端测试
   */
  async runFrontendTests() {
    console.log(chalk.bold.cyan('\n🖥️  开始前端功能测试'));
    console.log(chalk.gray('-'.repeat(60)));
    
    try {
      const frontendRunner = new FrontendTestRunner();
      await frontendRunner.runAllTests();
      
      // 收集前端测试结果
      this.allResults.frontend = frontendRunner.testUtils.testResults;
      
      console.log(chalk.green('\n✅ 前端测试完成'));
    } catch (error) {
      console.error(chalk.red(`\n❌ 前端测试失败: ${error.message}`));
      // 不中断整个测试流程
    }
  }

  /**
   * 生成测试报告
   */
  async generateTestReport() {
    console.log(chalk.yellow('\n📊 生成测试报告...'));
    
    // 合并所有测试结果
    const allTestResults = [...this.allResults.api, ...this.allResults.frontend];
    
    // 计算统计信息
    this.calculateSummary(allTestResults);
    
    // 生成HTML报告
    await this.generateHtmlReport(allTestResults);
    
    // 生成JSON报告
    await this.generateJsonReport(allTestResults);
    
    // 生成Markdown报告
    await this.generateMarkdownReport(allTestResults);
    
    console.log(chalk.green('✅ 测试报告生成完成'));
  }

  /**
   * 计算测试统计信息
   */
  calculateSummary(results) {
    this.allResults.summary.total = results.length;
    this.allResults.summary.passed = results.filter(r => r.status === 'passed').length;
    this.allResults.summary.failed = results.filter(r => r.status === 'failed').length;
    this.allResults.summary.duration = this.endTime - this.startTime;
    
    // 按模块统计
    const moduleStats = {};
    results.forEach(result => {
      if (!moduleStats[result.module]) {
        moduleStats[result.module] = { total: 0, passed: 0, failed: 0 };
      }
      moduleStats[result.module].total++;
      if (result.status === 'passed') {
        moduleStats[result.module].passed++;
      } else {
        moduleStats[result.module].failed++;
      }
    });
    
    this.allResults.summary.modules = moduleStats;
  }

  /**
   * 生成HTML测试报告
   */
  async generateHtmlReport(results) {
    const timestamp = moment().format('YYYY-MM-DD HH:mm:ss');
    const duration = moment.duration(this.allResults.summary.duration).humanize();
    
    const html = `
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>TodoList应用测试报告</title>
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; line-height: 1.6; color: #333; background: #f5f5f5; }
        .container { max-width: 1200px; margin: 0 auto; padding: 20px; }
        .header { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 30px; border-radius: 10px; margin-bottom: 30px; text-align: center; }
        .header h1 { font-size: 2.5em; margin-bottom: 10px; }
        .header p { font-size: 1.1em; opacity: 0.9; }
        .summary { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px; margin-bottom: 30px; }
        .summary-card { background: white; padding: 20px; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); text-align: center; }
        .summary-card h3 { color: #666; font-size: 0.9em; text-transform: uppercase; margin-bottom: 10px; }
        .summary-card .number { font-size: 2.5em; font-weight: bold; margin-bottom: 5px; }
        .passed { color: #27ae60; }
        .failed { color: #e74c3c; }
        .total { color: #3498db; }
        .duration { color: #f39c12; }
        .modules { background: white; padding: 30px; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); margin-bottom: 30px; }
        .modules h2 { margin-bottom: 20px; color: #2c3e50; }
        .module-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 15px; }
        .module-card { border: 1px solid #ddd; border-radius: 8px; padding: 15px; }
        .module-card h4 { margin-bottom: 10px; color: #34495e; }
        .module-stats { display: flex; justify-content: space-between; }
        .module-stats span { padding: 5px 10px; border-radius: 5px; font-size: 0.9em; }
        .results { background: white; padding: 30px; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
        .results h2 { margin-bottom: 20px; color: #2c3e50; }
        .test-item { border-bottom: 1px solid #eee; padding: 15px 0; }
        .test-item:last-child { border-bottom: none; }
        .test-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 5px; }
        .test-name { font-weight: bold; font-size: 1.1em; }
        .test-status { padding: 5px 15px; border-radius: 20px; color: white; font-size: 0.9em; }
        .status-passed { background: #27ae60; }
        .status-failed { background: #e74c3c; }
        .test-details { color: #666; font-size: 0.9em; }
        .test-error { background: #fff5f5; border: 1px solid #fed7d7; border-radius: 5px; padding: 10px; margin-top: 10px; color: #c53030; font-family: monospace; font-size: 0.8em; }
        .footer { text-align: center; margin-top: 30px; color: #666; }
        @media (max-width: 768px) {
            .container { padding: 10px; }
            .header { padding: 20px; }
            .header h1 { font-size: 2em; }
            .summary { grid-template-columns: repeat(2, 1fr); }
            .module-grid { grid-template-columns: 1fr; }
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1>📋 TodoList应用测试报告</h1>
            <p>测试时间: ${timestamp} | 总耗时: ${duration}</p>
        </div>
        
        <div class="summary">
            <div class="summary-card">
                <h3>总测试数</h3>
                <div class="number total">${this.allResults.summary.total}</div>
            </div>
            <div class="summary-card">
                <h3>通过测试</h3>
                <div class="number passed">${this.allResults.summary.passed}</div>
            </div>
            <div class="summary-card">
                <h3>失败测试</h3>
                <div class="number failed">${this.allResults.summary.failed}</div>
            </div>
            <div class="summary-card">
                <h3>成功率</h3>
                <div class="number duration">${this.allResults.summary.total > 0 ? Math.round((this.allResults.summary.passed / this.allResults.summary.total) * 100) : 0}%</div>
            </div>
        </div>
        
        <div class="modules">
            <h2>📊 模块测试统计</h2>
            <div class="module-grid">
                ${Object.entries(this.allResults.summary.modules).map(([module, stats]) => `
                    <div class="module-card">
                        <h4>${this.getModuleDisplayName(module)}</h4>
                        <div class="module-stats">
                            <span style="background: #3498db; color: white;">总计: ${stats.total}</span>
                            <span style="background: #27ae60; color: white;">通过: ${stats.passed}</span>
                            <span style="background: #e74c3c; color: white;">失败: ${stats.failed}</span>
                        </div>
                    </div>
                `).join('')}
            </div>
        </div>
        
        <div class="results">
            <h2>📝 详细测试结果</h2>
            ${results.map(result => `
                <div class="test-item">
                    <div class="test-header">
                        <span class="test-name">${result.testName}</span>
                        <span class="test-status status-${result.status}">${result.status === 'passed' ? '✅ 通过' : '❌ 失败'}</span>
                    </div>
                    <div class="test-details">
                        <strong>模块:</strong> ${this.getModuleDisplayName(result.module)} | 
                        <strong>耗时:</strong> ${result.duration}ms | 
                        <strong>描述:</strong> ${result.description}
                    </div>
                    ${result.error ? `<div class="test-error">错误信息: ${result.error}</div>` : ''}
                </div>
            `).join('')}
        </div>
        
        <div class="footer">
            <p>报告生成时间: ${timestamp}</p>
            <p>TodoList应用自动化测试系统</p>
        </div>
    </div>
</body>
</html>
    `;
    
    const reportPath = path.join(__dirname, 'results', `test-report-${moment().format('YYYY-MM-DD-HH-mm-ss')}.html`);
    await fs.writeFile(reportPath, html, 'utf8');
    
    console.log(chalk.green(`📄 HTML报告已生成: ${reportPath}`));
  }

  /**
   * 生成JSON测试报告
   */
  async generateJsonReport(results) {
    const reportData = {
      timestamp: moment().format('YYYY-MM-DD HH:mm:ss'),
      summary: this.allResults.summary,
      results: results,
      environment: {
        serverUrl: config.server.baseUrl,
        frontendUrl: config.frontend.baseUrl,
        nodeVersion: process.version,
        platform: process.platform
      }
    };
    
    const reportPath = path.join(__dirname, 'results', `test-results-${moment().format('YYYY-MM-DD-HH-mm-ss')}.json`);
    await fs.writeFile(reportPath, JSON.stringify(reportData, null, 2), 'utf8');
    
    console.log(chalk.green(`📄 JSON报告已生成: ${reportPath}`));
  }

  /**
   * 生成Markdown测试报告
   */
  async generateMarkdownReport(results) {
    const timestamp = moment().format('YYYY-MM-DD HH:mm:ss');
    const duration = moment.duration(this.allResults.summary.duration).humanize();
    
    const markdown = `
# TodoList应用测试报告

**测试时间:** ${timestamp}  
**总耗时:** ${duration}  
**服务器地址:** ${config.server.baseUrl}  
**前端地址:** ${config.frontend.baseUrl}

## 📊 测试统计

| 指标 | 数值 |
|------|------|
| 总测试数 | ${this.allResults.summary.total} |
| 通过测试 | ${this.allResults.summary.passed} |
| 失败测试 | ${this.allResults.summary.failed} |
| 成功率 | ${this.allResults.summary.total > 0 ? Math.round((this.allResults.summary.passed / this.allResults.summary.total) * 100) : 0}% |

## 📋 模块测试统计

| 模块 | 总计 | 通过 | 失败 | 成功率 |
|------|------|------|------|--------|
${Object.entries(this.allResults.summary.modules).map(([module, stats]) => {
  const successRate = stats.total > 0 ? Math.round((stats.passed / stats.total) * 100) : 0;
  return `| ${this.getModuleDisplayName(module)} | ${stats.total} | ${stats.passed} | ${stats.failed} | ${successRate}% |`;
}).join('\n')}

## 📝 详细测试结果

${results.map(result => `
### ${result.status === 'passed' ? '✅' : '❌'} ${result.testName}

- **模块:** ${this.getModuleDisplayName(result.module)}
- **状态:** ${result.status === 'passed' ? '通过' : '失败'}
- **耗时:** ${result.duration}ms
- **描述:** ${result.description}
${result.error ? `- **错误信息:** \`${result.error}\`` : ''}
`).join('')}

---

*报告生成时间: ${timestamp}*  
*TodoList应用自动化测试系统*
    `;
    
    const reportPath = path.join(__dirname, 'results', `test-report-${moment().format('YYYY-MM-DD-HH-mm-ss')}.md`);
    await fs.writeFile(reportPath, markdown, 'utf8');
    
    console.log(chalk.green(`📄 Markdown报告已生成: ${reportPath}`));
  }

  /**
   * 获取模块显示名称
   */
  getModuleDisplayName(module) {
    const moduleNames = {
      'USER_AUTH': '👤 用户认证',
      'LIST_MANAGEMENT': '📋 清单管理',
      'TASK_MANAGEMENT': '✅ 任务管理',
      'RECURRING_TASKS': '🔄 重复任务',
      'DATA_SYNC': '🔄 数据同步',
      'DATA_MANAGEMENT': '💾 数据管理',
      'STATISTICS': '📊 统计分析',
      'SETTINGS': '⚙️ 应用设置',
      'AI_FEATURES': '🤖 AI功能',
      'APPLICATION_INIT': '🚀 应用初始化',
      'USER_INTERFACE': '👤 用户界面',
      'TASK_MANAGEMENT_UI': '✅ 任务管理界面',
      'LIST_MANAGEMENT_UI': '📋 清单管理界面',
      'POMODORO_UI': '🍅 番茄钟界面',
      'WHITE_NOISE_UI': '🎵 白噪音界面',
      'STATISTICS_UI': '📊 统计界面',
      'CALENDAR_UI': '📅 日历界面',
      'SETTINGS_UI': '⚙️ 设置界面',
      'RESPONSIVE_DESIGN': '📱 响应式设计'
    };
    
    return moduleNames[module] || module;
  }

  /**
   * 打印最终测试摘要
   */
  async printFinalSummary() {
    const duration = moment.duration(this.allResults.summary.duration).humanize();
    const successRate = this.allResults.summary.total > 0 ? 
      Math.round((this.allResults.summary.passed / this.allResults.summary.total) * 100) : 0;
    
    console.log(chalk.gray('\n' + '='.repeat(80)));
    console.log(chalk.bold.blue('🎯 测试执行完成'));
    console.log(chalk.gray('='.repeat(80)));
    
    console.log(chalk.cyan(`📊 测试统计:`));
    console.log(chalk.white(`   总测试数: ${this.allResults.summary.total}`));
    console.log(chalk.green(`   通过测试: ${this.allResults.summary.passed}`));
    console.log(chalk.red(`   失败测试: ${this.allResults.summary.failed}`));
    console.log(chalk.yellow(`   成功率: ${successRate}%`));
    console.log(chalk.blue(`   总耗时: ${duration}`));
    
    console.log(chalk.cyan(`\n📁 测试报告:`));
    console.log(chalk.white(`   报告目录: ${path.join(__dirname, 'results')}`));
    
    if (this.allResults.summary.failed > 0) {
      console.log(chalk.red(`\n⚠️  发现 ${this.allResults.summary.failed} 个失败的测试，请查看详细报告`));
      process.exit(1);
    } else {
      console.log(chalk.green(`\n🎉 所有测试通过！应用功能正常`));
      process.exit(0);
    }
  }
}

// 处理命令行参数
function parseArguments() {
  const args = process.argv.slice(2);
  const options = {
    apiOnly: args.includes('--api-only'),
    frontendOnly: args.includes('--frontend-only'),
    help: args.includes('--help') || args.includes('-h')
  };
  
  if (options.help) {
    console.log(`
TodoList应用自动化测试工具

使用方法:
  node run-tests.js [选项]

选项:
  --api-only      只运行API测试
  --frontend-only 只运行前端测试
  --help, -h      显示帮助信息

示例:
  node run-tests.js              # 运行所有测试
  node run-tests.js --api-only   # 只运行API测试
  node run-tests.js --frontend-only # 只运行前端测试
`);
    process.exit(0);
  }
  
  return options;
}

// 主入口
if (require.main === module) {
  const options = parseArguments();
  const runner = new MainTestRunner();
  
  // 根据参数决定运行哪些测试
  if (options.apiOnly) {
    runner.runApiTests().then(() => runner.generateTestReport()).catch(console.error);
  } else if (options.frontendOnly) {
    runner.runFrontendTests().then(() => runner.generateTestReport()).catch(console.error);
  } else {
    runner.runAllTests().catch(console.error);
  }
}

module.exports = MainTestRunner;